<?php
/**
 * @author Inhere
 * @version v1.0
 * Date : 2014-9-1
 * Name : 公共库 记录排序 RecordSort.php
 * 注意：默认记录展示情况是倒序排列(由上到下排序值减小)
 * use ：
 *     $request            = Yii::app()->getRequest();
 *     $int_id             = $request->getParam('id');
 *     $int_rank           = $request->getParam('rank');
 *     $int_sort_request   = $request->getParam('sort_request');
 *     $sort               = new RecordSort();
 *     $sort->tableName    = 'Faq';
 *     # 1.可在查询列表时 先存储首尾排序值 到 SESSION，实例化时会读取
 *     # 2. 也可在这里设置
 *       // $sort->firstRank     = Yii::app()->session['first_rank'];
 *       // $sort->lastRank      = Yii::app()->session['last_rank'];
 *      # 多传一个参数 $int_sort_request，标明请求 向上还是向下
 *      if ((int)$int_sort_request == 1) {
 *           $sort->moveUp($int_id,$int_rank);
 *      } else {
 *           $sort->moveDown($int_id,$int_rank);
 *      }
 *
 * 置顶置底 操作类似
 * moveTop($int_id,$old_rank,$table_name='')
 * 置底
 * moveBottom($int_id,$old_rank,$table_name='')
 *
 */
namespace ulue\ext\db;

class RecordSort
{
    public $addCondition    = '';       # 额外的条件 @example记录有分类，分类记录单独排序
    public $tableName;                  # 操作表名
    public $tablePK         = 'id';     # 主键列名
    public $sortField       = 'rank';   # 排序字段
    public $preRecord       = array();  # 前面一记录的信息
    public $sufRecord       = array();  # 后面一记录的信息
    public $firstRank       = '';       # 第一条记录 排序值
    public $lastRank        = '';       # 最后一条记录 排序值

    public function __construct()
    {
        $this->firstRank     = isset($_SESSION['first_rank']) ? $_SESSION['first_rank'] : $this->firstRank;
        $this->lastRank      = isset($_SESSION['last_rank']) ? $_SESSION['last_rank'] : $this->lastRank;
    }

    /*
    1.array(
        'firstRank' => rankValue,
        'lastRank' => rankValue
     )
    2. ('firstRank','rankValue')
     */
    public function setValue($name,$value='')
    {
        if (is_array($name)){
            foreach ($name as $key => $val) {
                if (isset($this->$key)) {
                    $this->$key = $val;
                }
            }
        } else if (isset($this->$name)){
            $this->$name = $value;
        }
    }

    /**
     * execute 执行排序，
     * @param [type]  $table_name   [操作表名称,无前缀]
     * @param [type]  $int_id       [当前记录 Id]
     * @param [type]  $old_rank     [当前记录的排序值]
     * @param integer $rankRequest       [排序请求：1 向上 0 向下]
     */
    public function execute($int_id,$old_rank,$table_name='',$rankRequest='up')
    {
        $this->tableNameCheck($table_name);
        $table_name     = '{{'.$this->tableName.'}}';
        $PK             = $this->tablePK;
        $field          = $this->sortField;
        $whereCondition = $this->addCondition;
        // md($int_id,$old_rank,$table_name,$rankRequest,$PK,$field,$this->firstRank,$this->lastRank);
        switch ((string)$rankRequest) {
            case 'up':      # 上移一位
                $this->recordCheck($old_rank);
                # 获取前面一记录的信息
                $str_sql            = "SELECT {$PK},{$field} FROM ".$table_name." WHERE {$whereCondition} {$field}>'{$old_rank}' ORDER BY rank ASC LIMIT 1";
                $pre_record         = Ulue::$app->db->createSql($str_sql)->queryRow();
                $pre_record_rank    = $pre_record[$field];
                $pre_record_id      = $pre_record[$PK];
                $sql                = "UPDATE ".$table_name." SET {$field}='{$pre_record_rank}' WHERE {$PK}='{$int_id}';
                        UPDATE ".$table_name." SET {$field}='{$old_rank}' WHERE {$PK}='{$pre_record_id}';";
                break;
            case 'down':    # 下移一位
                $this->recordCheck($old_rank,0);
                # 获取后面一记录的信息
                $str_sql            = "SELECT {$PK},{$field} FROM ".$table_name." WHERE {$whereCondition} {$field}<'{$old_rank}' ORDER BY rank DESC LIMIT 1";
                $suf_record         = Ulue::$app->db->createSql($str_sql)->queryRow();
                $suf_record_rank    = $suf_record[$field];
                $suf_record_id      = $suf_record[$PK];
                $sql                = "UPDATE ".$table_name." SET {$field}='{$suf_record_rank}' WHERE {$PK}='{$int_id}';
                        UPDATE ".$table_name." SET {$field}='{$old_rank}' WHERE {$PK}='{$suf_record_id}';";
                break;
            case 'top':     # 置顶
                $this->recordCheck($old_rank);
                $sql            = "UPDATE ".$table_name." SET {$field}=".((int)$this->firstRank+1)." WHERE {$PK}=".$int_id;
                break;
            case 'bottom':  # 置底
                $this->recordCheck($old_rank,0);
                $sql            = "UPDATE ".$table_name." SET {$field}=".((int)$this->lastRank-1)." WHERE {$PK}=".$int_id;
                break;
            default:
                break;
        }
        $bool_ret = Yii::app()->db->createCommand($sql)->query();
        if ($bool_ret) {
            $this->showInfo(array('message' => "操作成功！",'statusCode' => 200));
        } else { // has error
            $this->showInfo(array('message' => "操作失败！请重试...",'statusCode' => 300));
        }
    }

    public function addCondition($value)
    {
        $this->addCondition = $value. ' AND ';
        return true;
    }
    /**
     * 上移一位
     * @param [type]  $int_id       [当前记录 Id]
     * @param [type]  $old_rank     [当前记录的排序值]
     * @param [type]  $table_name   [操作表名称,无前缀]
     */
    public function moveUp($int_id,$old_rank,$table_name='')
    {
        $this->execute($int_id,$old_rank,$table_name,'up');
    }
    # 下移一位
    public function moveDown($int_id,$old_rank,$table_name='')
    {
        $this->execute($int_id,$old_rank,$table_name,'down');
    }
    # 置顶
    public function moveTop($int_id,$old_rank,$table_name='')
    {
        $this->execute($int_id,$old_rank,$table_name,'top');
    }
    # 置底
    public function moveBottom($int_id,$old_rank,$table_name='')
    {
        $this->execute($int_id,$old_rank,$table_name,'bottom');
    }
    private function tableNameCheck($table_name)
    {
        $this->tableName     = empty($table_name) ? $this->tableName : $table_name;
        if (empty($this->tableName)) {
            $this->showInfo( array('message'=>'必须传入或设置要操作的表名称(无需前缀)！','statusCode'=>300) );
        }
    }
    /**
     * 首尾记录 检查
     * @param int $old_rank 当前的排序值
     * @param int $moveDirection 移动方向
     */
    private function recordCheck($old_rank,$moveDirection=1)
    {
        $first_rank     = $this->firstRank;
        $last_rank      = $this->lastRank;
        if ($this->firstRank=='' || $this->lastRank=='') {
            $this->showInfo( array('message'=>'必须传入首尾记录的排序值！','statusCode'=>300) );
        }
        # 阻止第一条记录升序
        if ( (int)$moveDirection == 1 && $first_rank == $old_rank) {
            $this->showInfo( array('message'=>'记录已在最顶部！','statusCode'=>300) );
        # 阻止最后一条记录降序
        } else if ((int)$moveDirection == 0 && $last_rank == $old_rank){
            $this->showInfo( array('message'=>'记录已在最底部！','statusCode'=>300) );
        }
    }
    # 错误输出
    private function showInfo($arr = array())
    {
        $msg = json_encode( $arr );
        exit($msg);
    }
}
